#include <stdio.h>
#include "util.h"
#include "absyn.h"
#include "scan.h"
#include <stdlib.h>
#include "symbol.h"

extern void S_destroySymbol(S_symbol sym);


string exptypes[] =
{
	"Var", "Int", "String", "FunctionCall", "Operation",
	"Record", "Assign", "If", "While", "For", "Sequance",
	"Declare", "ASM"
};

string vartypes[] =
{
	"SimpleVar", "FieldVar", "SubscriptVar"
};

string oper[] =
{
	"plus", "minus", "times", "divide", "equal", "not-equal",
	"less-than", "less-equal", "grater-than", "grater-equal",
	"and", "or"
};

#ifndef NULL
#define NULL 0
#endif

void scanTree(A_exp exp, int depth);

void printIndice(int depth)
{
	int i;
	for(i=depth; i>0; i--)
		printf("    ");
}

void scanVar(A_var var, int depth)
{

	if (var == 0)
		return;

	printf("\n");
	printIndice(depth);
	printf("%s:", vartypes[var->kind]);
	switch(var->kind)
	{
	case A_simpleVar:
		{
			string name = S_name(var->u.simple);
			printf("%s", name);
			break;
		}
	case A_fieldVar:
		{
			scanVar(var->u.field.main, depth+1);
			scanVar(var->u.field.sub, depth+1);
			break;
		}
	case A_subscriptVar:
		{
			string name = S_name(var->u.subscript.name);
			int i;
			printf("\t%s", name);
			for (i=0; i< var->u.subscript.size; i++)
			{
			    scanTree(var->u.subscript.sub[i], depth+1);
			}

			break;
		}
	}
}


void scanTy(A_ty ty, int depth)
{
	switch(ty->kind)
	{
	case A_nameTy:
	{
		printf("%s -> %s", S_name(ty->u.name.name),
				S_name(ty->u.name.ty));
		break;
	}
	case A_recordTy:
	{
		A_fieldList ptr = ty->u.record.record;
		while (ptr)
		{
			printf("%s %s; ", S_name(ptr->data->name),
				S_name(ptr->data->typ));
			ptr = ptr->next;
		}
		break;
	}
	case A_arrayTy:
	{
		A_subList subs = ty->u.array.size;
		printf("%s", S_name(ty->u.array.type));
		while(subs)
		{
			printf("[%d]", subs->data->u.intt);
			subs = subs->next;
		}
		break;
	}
	}
	printf("\n");
}

void scanDec(A_dec dec, int depth)
{
	if (dec->kind == A_funDec)
	{
		printf("Function %s: %s",
			S_name(dec->u.fun.name),
			S_name(dec->u.fun.result));
		scanTree(dec->u.fun.body, depth+1);
	}
	else if (dec->kind == A_varDec)
	{
		printf("Var: %s", S_name(dec->u.var.var));

	}
	else if (dec->kind == A_typeDec)
	{
		A_ty ty = dec->u.ty;
		printf("Typedef: ");
		switch(ty->kind)
		{
		case A_nameTy:
			{
				printf("[Namety] %s -> %s", S_name(ty->u.name.name),
					S_name(ty->u.name.ty));
				break;
			}
		case A_recordTy:
			{
				printf("[Record] %s", S_name(ty->u.record.name));
				//scanTy(dec->u.ty->u.record.record
				break;
			}
		case A_arrayTy:
			{
				A_subList sub = ty->u.array.size;
				printf("[Array] %s", S_name(ty->u.array.type));
				while (sub)
				{
					printf("[%d]", sub->data->u.intt);
					sub = sub->next;
				}
				printf(" -> %s", S_name(ty->u.array.name));
				break;
			}
		}

	}
}


void scanTree(A_exp exp, int depth)
{
	if (exp == 0)
		return;

	printf("\n");
	printIndice(depth);
	printf("%s[%d]\t\t", exptypes[exp->kind], exp->pos);

	switch(exp->kind)
	{
	case A_asmExp:
	{
		A_asmList p = exp->u.asmm;
		printf("\n");
		printIndice(depth+1);
		printf("[Assembly code below]\n");
		while (p)
		{
			printIndice(depth+1);
			printf("  %s\n", p->code);
			p = p->next;
		};
		printIndice(depth+1);
		printf("[End of assembly]\n");
		break;
	}
	case A_varExp:
	{
		scanVar(exp->u.var, depth+1);
	        break;
	}
	case A_intExp:
		printf(": %d", exp->u.intt);
		break;
	case A_stringExp:
		printf(": %s\n", exp->u.stringg);
		break;
	case A_seqExp:
	{
		A_expList l = exp->u.seq->next;

		scanTree(exp->u.seq->data, depth+1);
		while(l)
		{
			scanTree(l->data, depth+1);
			l = l->next;
		}
		break;
	}
	case A_assignExp:
		scanVar(exp->u.assign.var, depth+1);
		scanTree(exp->u.assign.exp, depth+1);
		break;
	case A_opExp:
		printf(": %s", oper[exp->u.op.oper]);
		scanTree(exp->u.op.left, depth+1);
		scanTree(exp->u.op.right, depth+1);
		break;
	case A_ifExp:
		printf("\n");
		printIndice(depth+1);
		printf("Test:");
		scanTree(exp->u.iff.test, depth+1);
		printf("\n");
		printIndice(depth+1);
		printf("Then:");
		scanTree(exp->u.iff.then, depth+1);
		if (exp->u.iff.elsee)
		{
			printf("\n");
			printIndice(depth+1);
			printf("Else:");
			scanTree(exp->u.iff.elsee, depth+1);
		}
		break;
	case A_decExp:
	{
		scanDec(exp->u.dec, depth+1);
		break;
	}
	case A_callExp:
	{
		A_expList p = exp->u.call.args;
		printf("%s\n", S_name(exp->u.call.func));
		while (p)
		{
			scanTree(p->data, depth+1);
			p=p->next;
		}
		break;
	}
	default:
		printf("others\n");
		break;
	}
};

void destoryVar(A_var v)
{
	if (v==0)
		return;

	switch(v->kind)
	{
	case A_simpleVar:
	{
		//S_destroySymbol((S_symbol)v->u.simple);
		break;
	}
	case A_fieldVar:
	{
		//S_destorySymbol(v->u.field.sym);
		//destroyVar(v->u.field.var);
		break;
	}
	case A_subscriptVar:
	{
		break;
	}
	};
	free(v);
};

void destroyExpList(A_expList list)
{
	if ( list == 0)
		return;
	destroyExp(list->data);
	destroyExpList(list->next);
	free(list);
};

void destroyExp(A_exp exp)
{
	if ( exp == 0)
		return;

	switch(exp->kind)
	{
	case A_varExp:
		free(exp->u.var);
		printf("destroying var exp\n");
		break;
	case A_intExp:		// nothing to be deleted here
		break;
	case A_stringExp:
		free(exp->u.stringg);
		break;
	case A_callExp:		// to be done
		break;
	case A_opExp:
		break;
	case A_recordExp:
		break;
	case A_ifExp:
		break;
	case A_whileExp:
		break;
	case A_forExp:
		break;
	case A_assignExp:
		destoryVar(exp->u.assign.var);
		destroyExp(exp->u.assign.exp);
		printf("destroying assign exp\n");
		break;
	case A_seqExp:
		destroyExpList(exp->u.seq);
		printf("destroying exp list\n");
		break;
	default:
		break;
	}
	free(exp);
}
